package cn.tedu.lbs.marketing.web.service;

import cn.tedu.lbs.basic.api.BasicApi;
import cn.tedu.lbs.marketing.web.repository.CouponCodeRepository;
import cn.tedu.lbs.marketing.web.repository.CouponRepository;
import cn.tedu.lbs.marketing.web.util.AuthenticationContextUtil;
import cn.tedu.lbs.stock.api.StockApi;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sun.xml.internal.bind.v2.TODO;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.pojo.basic.dto.AdminDTO;
import com.tarena.lbs.pojo.basic.po.AdminPO;
import com.tarena.lbs.pojo.marketing.param.CouponParam;
import com.tarena.lbs.pojo.marketing.po.CouponCodePO;
import com.tarena.lbs.pojo.marketing.po.CouponPO;
import com.tarena.lbs.pojo.marketing.query.CouponQuery;
import com.tarena.lbs.pojo.marketing.vo.CouponVO;
import com.tarena.lbs.pojo.stock.param.CouponStockParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CouponService {
    @Autowired
    private CouponRepository couponRepository;
    @Autowired
    private CouponCodeRepository couponCodeRepository;
    public PageResult<CouponVO> pageList(CouponQuery couponQuery) throws BusinessException {
        Integer businessId = checkAndGetBusinessId();
        List<CouponPO> pos= getCouponByBusinessId(businessId);
        PageResult<CouponVO> voPage=new PageResult<>(10,1);
        voPage.setTotal(100L);
        if (pos!=null&&pos.size()>0){
            voPage.setObjects(pos.stream().map(po -> {
                CouponVO vo = new CouponVO();
                BeanUtils.copyProperties(po, vo);
                return vo;
            }).collect(Collectors.toList()));
        }
        return voPage;
    }

    private List<CouponPO> getCouponByBusinessId(Integer businessId) {
        //select * from coupon where business_id=?
        QueryWrapper<CouponPO> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("business_id",businessId);
        return couponRepository.list(queryWrapper);
    }

    private Integer checkAndGetBusinessId() throws BusinessException {
        //1.拿到认证对象
        UserPrinciple userPrinciple = AuthenticationContextUtil.get();
        //2.断言空
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户认证解析失败"));
        //3.拿到角色
        Roles role = userPrinciple.getRole();
        Integer businessId=null;
        //4.如果角色是SHOP 需要给businessId赋值
        if (role==Roles.SHOP){
            businessId=getAdminBusinessId(userPrinciple.getId());
            Asserts.isTrue
                    (businessId==null,new BusinessException("-2","登录用户根本不存在"));
        }
        return businessId;
    }
    @DubboReference
    private BasicApi basicApi;
    private Integer getAdminBusinessId(Integer id) throws BusinessException {
        AdminDTO adminDTO = basicApi.getAdminDetail(id);
        Asserts.isTrue(adminDTO==null,new BusinessException("-2","商家账号根本不存在"));
        return adminDTO.getBusinessId();
    }

    public void save(CouponParam couponParam) throws BusinessException {
        //1.检查并获取businessId
        Integer businessId = checkAndGetBusinessId();
        //2.组织一个couponPO 写入到数据库
        Integer couponId=saveCoupon(businessId,couponParam);
        //3.couponPO写完 生成id 绑定 生成List<CouponCodePO>
        /*long start=System.currentTimeMillis();
        saveCouponCode(couponId,couponParam,businessId);
        long end=System.currentTimeMillis();
        log.info("优惠券码批量写入耗时:{}MS",end-start);*/
        //4.远程调用 生成库存初始化数据
        initStock(couponId,couponParam,businessId);
    }
    @DubboReference
    private StockApi stockApi;
    private void initStock(Integer couponId, CouponParam couponParam,Integer businessId) {
        //组织一个CouponStockParam 调用远程方法
        CouponStockParam param=new CouponStockParam();
        param.setCouponId(couponId);
        param.setBusinessId(businessId);
        param.setNum(couponParam.getMaxUsageLimit());
        stockApi.initCouponStock(param);
        log.info("当前优惠券:{},初始库存:{}个",couponId,couponParam.getMaxUsageLimit());
    }

    private void saveCouponCode(Integer couponId, CouponParam couponParam,Integer businessId) {
        //组织集合数据 调用couponCode仓储层批量写入 100 1000 100000 coupon_code
        List<CouponCodePO> pos=new ArrayList<>();
        Integer count = couponParam.getMaxUsageLimit();//本次优惠券发行总量上限
        //使用count作为上限实现for循环
        for (int i = 0; i < count; i++) {
            //初始化一个优惠券券码数据 添加pos
            CouponCodePO couponCodePO = new CouponCodePO();
            //1.关联优惠券id
            couponCodePO.setCouponId(couponId);
            //2.生成唯一编码
            couponCodePO.setCouponCode(UUID.randomUUID().toString());
            //3.时间
            couponCodePO.setCreateAt(new Date());
            couponCodePO.setUpdateAt(new Date());
            //4.券码关联的商家 冗余字段(减少关联查询)
            couponCodePO.setBusinessId(businessId);
            //5.状态 没有领取0 已领取1 已超时2
            couponCodePO.setStatus(0);
            pos.add(couponCodePO);
        }
        //批量写入 insert into table (field) values (),(),()
        couponCodeRepository.saveBatch(pos,1000);
    }

    private Integer saveCoupon(Integer businessId, CouponParam couponParam) throws BusinessException {
        //组织封装一个po 仓储层save写入数据库
        CouponPO po = new CouponPO();
        BeanUtils.copyProperties(couponParam,po);
        //1.businessId
        po.setBusinessId(businessId);
        //2.两个状态 防止 数据库有非空校验
        po.setStatus(0);//业务状态 0待审核 1已通过 2驳回
        po.setEnableStatus(1);//管理启用状态 0禁用 1启用
        //3.时间字段
        po.setCreateAt(new Date());
        po.setUpdateAt(new Date());
        //4.入参日期 springmvc 对字符串格式日期"2025-03-19" 不能 自动转化成date localDateTime
        //第一种方案 通过配置类 添加springmvc转化功能 把字符串自动转化成日期(最优解)
        //第二种方案 手动转化
        String startStr=couponParam.getStartDate();
        String endStr=couponParam.getEndDate();
        try{
            Date startDate= DateUtils.parseDate(startStr,"yyyy-MM-dd HH:mm:ss");
            po.setStartDate(startDate);
            Date endDate= DateUtils.parseDate(endStr,"yyyy-MM-dd HH:mm:ss");
            po.setEndDate(endDate);
        }catch (Exception e){
            throw new BusinessException("-2","日期字符串转化失败");
        }
        couponRepository.save(po);
        return po.getId();
    }

    public CouponVO detail(Integer id) throws BusinessException {
        CouponPO po = couponRepository.getById(id);
        Asserts.isTrue(po==null,new BusinessException("-2","优惠券不存在"));
        CouponVO vo=new CouponVO();
        BeanUtils.copyProperties(po,vo);
        return vo;
    }
}
